*/ public function register(): array { return [ T_OPEN_SQUARE_BRACKET, ]; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint * @param int $bracketOpenerPointer */ public function process(File $phpcsFile, $bracketOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $assignmentPointer = TokenHelper::findNextEffective($phpcsFile, $tokens[$bracketOpenerPointer]['bracket_closer'] + 1); if ($tokens[$assignmentPointer]['code'] !== T_EQUAL) { return; } /** @var int $variablePointer */ $variablePointer = TokenHelper::findPreviousEffective($phpcsFile, $bracketOpenerPointer - 1); if ($tokens[$variablePointer]['code'] !== T_VARIABLE) { return; } if (in_array($tokens[$variablePointer]['content'], [ '$GLOBALS', '$_SERVER', '$_REQUEST', '$_POST', '$_GET', '$_FILES', '$_ENV', '$_COOKIE', '$_SESSION', '$this', ], true)) { return; } $pointerBeforeVariable = TokenHelper::findPreviousEffective($phpcsFile, $variablePointer - 1); if (in_array($tokens[$pointerBeforeVariable]['code'], [T_OBJECT_OPERATOR, T_DOUBLE_COLON], true)) { return; } $scopeOwnerPointer = null; foreach (array_reverse($tokens[$variablePointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) { if (!in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) { continue; } $scopeOwnerPointer = $conditionPointer; break; } $scopeOwnerPointer ??= TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $variablePointer - 1); $scopeOpenerPointer = $tokens[$scopeOwnerPointer]['code'] === T_OPEN_TAG ? $scopeOwnerPointer : $tokens[$scopeOwnerPointer]['scope_opener']; $scopeCloserPointer = $tokens[$scopeOwnerPointer]['code'] === T_OPEN_TAG ? count($tokens) - 1 : $tokens[$scopeOwnerPointer]['scope_closer']; if (in_array($tokens[$scopeOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) { if ($this->isParameter($phpcsFile, $scopeOwnerPointer, $variablePointer)) { return; } if ( $tokens[$scopeOwnerPointer]['code'] === T_CLOSURE && $this->isInheritedVariable($phpcsFile, $scopeOwnerPointer, $variablePointer) ) { return; } } if ($this->hasExplicitCreation($phpcsFile, $scopeOpenerPointer, $scopeCloserPointer, $variablePointer)) { return; } $phpcsFile->addError('Implicit array creation is disallowed.', $variablePointer, self::CODE_IMPLICIT_ARRAY_CREATION_USED); } private function isParameter(File $phpcsFile, int $functionPointer, int $variablePointer): bool { $tokens = $phpcsFile->getTokens(); $variableName = $tokens[$variablePointer]['content']; $parameterPointer = TokenHelper::findNextContent( $phpcsFile, T_VARIABLE, $variableName, $tokens[$functionPointer]['parenthesis_opener'] + 1, $tokens[$functionPointer]['parenthesis_closer'], ); return $parameterPointer !== null; } private function isInheritedVariable(File $phpcsFile, int $closurePointer, int $variablePointer): bool { $tokens = $phpcsFile->getTokens(); $variableName = $tokens[$variablePointer]['content']; $usePointer = TokenHelper::findNext( $phpcsFile, T_USE, $tokens[$closurePointer]['parenthesis_closer'] + 1, $tokens[$closurePointer]['scope_opener'], ); if ($usePointer === null) { return false; } $parenthesisOpenerPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1); $inheritedVariablePointer = TokenHelper::findNextContent( $phpcsFile, T_VARIABLE, $variableName, $parenthesisOpenerPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'], ); return $inheritedVariablePointer !== null; } private function hasExplicitCreation(File $phpcsFile, int $scopeOpenerPointer, int $scopeCloserPointer, int $variablePointer): bool { $tokens = $phpcsFile->getTokens(); $variableName = $tokens[$variablePointer]['content']; for ($i = $scopeOpenerPointer + 1; $i < $variablePointer; $i++) { if ($tokens[$i]['code'] !== T_VARIABLE) { continue; } if ($tokens[$i]['content'] !== $variableName) { continue; } if (!ScopeHelper::isInSameScope($phpcsFile, $variablePointer, $i)) { continue; } $assignmentPointer = TokenHelper::findNextEffective($phpcsFile, $i + 1); if ($tokens[$assignmentPointer]['code'] === T_EQUAL) { return true; } $staticPointer = TokenHelper::findPreviousEffective($phpcsFile, $i - 1); if ($tokens[$staticPointer]['code'] === T_STATIC) { return true; } if ($this->isCreatedInForeach($phpcsFile, $i, $scopeCloserPointer)) { return true; } if ($this->isCreatedInList($phpcsFile, $i, $scopeOpenerPointer)) { return true; } if ($this->isCreatedByReferencedParameterInFunctionCall($phpcsFile, $i, $scopeOpenerPointer)) { return true; } if ($this->isImportedUsingGlobalStatement($phpcsFile, $i)) { return true; } } return false; } private function isCreatedInList(File $phpcsFile, int $variablePointer, int $scopeOpenerPointer): bool { $tokens = $phpcsFile->getTokens(); $parenthesisOpenerPointer = TokenHelper::findPrevious( $phpcsFile, [T_OPEN_PARENTHESIS, T_OPEN_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET], $variablePointer - 1, $scopeOpenerPointer, ); if ($parenthesisOpenerPointer === null) { return false; } if ($tokens[$parenthesisOpenerPointer]['code'] === T_OPEN_PARENTHESIS) { if ($tokens[$parenthesisOpenerPointer]['parenthesis_closer'] < $variablePointer) { return false; } $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); return $tokens[$pointerBeforeParenthesisOpener]['code'] === T_LIST; } return $tokens[$parenthesisOpenerPointer]['bracket_closer'] > $variablePointer; } private function isCreatedInForeach(File $phpcsFile, int $variablePointer, int $scopeCloserPointer): bool { $tokens = $phpcsFile->getTokens(); $parenthesisCloserPointer = TokenHelper::findNext($phpcsFile, T_CLOSE_PARENTHESIS, $variablePointer + 1, $scopeCloserPointer); return $parenthesisCloserPointer !== null && array_key_exists('parenthesis_owner', $tokens[$parenthesisCloserPointer]) && $tokens[$tokens[$parenthesisCloserPointer]['parenthesis_owner']]['code'] === T_FOREACH && $tokens[$parenthesisCloserPointer]['parenthesis_opener'] < $variablePointer; } private function isCreatedByReferencedParameterInFunctionCall(File $phpcsFile, int $variablePointer, int $scopeOpenerPointer): bool { $tokens = $phpcsFile->getTokens(); $parenthesisOpenerPointer = TokenHelper::findPrevious($phpcsFile, T_OPEN_PARENTHESIS, $variablePointer - 1, $scopeOpenerPointer); if ( $parenthesisOpenerPointer === null || $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] < $variablePointer ) { return false; } $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); return $tokens[$pointerBeforeParenthesisOpener]['code'] === T_STRING; } private function isImportedUsingGlobalStatement(File $phpcsFile, int $variablePointer): bool { $tokens = $phpcsFile->getTokens(); $startOfStatement = $phpcsFile->findStartOfStatement($variablePointer, T_COMMA); return $tokens[$startOfStatement]['code'] === T_GLOBAL; } }